home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / uucp-104.lha / uucp-1.04 / uustat.c < prev    next >
C/C++ Source or Header  |  1993-02-13  |  53KB  |  2,242 lines

  1. /* uustat.c
  2.    UUCP status program
  3.  
  4.    Copyright (C) 1991, 1992 Ian Lance Taylor
  5.  
  6.    This file is part of the Taylor UUCP package.
  7.  
  8.    This program is free software; you can redistribute it and/or
  9.    modify it under the terms of the GNU General Public License as
  10.    published by the Free Software Foundation; either version 2 of the
  11.    License, or (at your option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful, but
  14.    WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.    General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22.    The author of the program may be contacted at ian@airs.com or
  23.    c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
  24.    */
  25.  
  26. #include "uucp.h"
  27.  
  28. #if USE_RCS_ID
  29. const char uustat_rcsid[] = "$Id: uustat.c,v 1.32 1992/12/17 04:43:27 ian Rel $";
  30. #endif
  31.  
  32. #include <ctype.h>
  33. #include <errno.h>
  34.  
  35. #if HAVE_TIME_H
  36. #include <time.h>
  37. #endif
  38.  
  39. #include "getopt.h"
  40.  
  41. #include "uudefs.h"
  42. #include "uuconf.h"
  43. #include "system.h"
  44.  
  45. /* The uustat program permits various listings and manipulations of
  46.    files in the spool directory.  This implementation supports the
  47.    following switches:
  48.  
  49.    -a list all jobs
  50.    -Blines number of lines of standard input to mail
  51.    -ccommand list only executions of specified command
  52.    -Ccommand list only jobs other than executions of specified command
  53.    -e list execute jobs rather than command requests
  54.    -i ask user whether to kill each listed job
  55.    -Ifile set configuration file name
  56.    -kjobid kill job with specified ID
  57.    -K kill each listed job
  58.    -m report status for all remote machines
  59.    -M mail uucp about each job killed with -K
  60.    -N mail requestor about each job killed with -K
  61.    -ohour report jobs older than specified number of hours
  62.    -p do "ps -flp" on all processes holding lock files (Unix specific)
  63.    -q list number of jobs for all systems
  64.    -Q don't list jobs, just do -K processing
  65.    -rjobid rejuvenate job with specified ID
  66.    -ssystem report on all jobs for specified system
  67.    -Ssystem report on all jobs other than for specified system
  68.    -uuser report on all jobs for specified user
  69.    -Uuser report on all jobs other than for specified user
  70.    -Wcomment comment to include in mail messages
  71.    -xdebug set debugging level
  72.    -yhour report jobs younger than specified number of hours  */
  73.  
  74. /* The program name.  */
  75. char abProgram[] = "uustat";
  76.  
  77. /* What to do with a job that matches the selection criteria; these
  78.    values may be or'red together.  */
  79. #define JOB_SHOW (01)
  80. #define JOB_INQUIRE (02)
  81. #define JOB_KILL (04)
  82. #define JOB_MAIL (010)
  83. #define JOB_NOTIFY (020)
  84.  
  85. /* This structure is used to accumulate all the lines in a single
  86.    command file, so that they can all be displayed at once and so that
  87.    executions can be displayed reasonably.  */
  88.  
  89. struct scmdlist
  90. {
  91.   struct scmdlist *qnext;
  92.   struct scmd s;
  93.   long itime;
  94. };
  95.  
  96. /* Local functions.  */
  97.  
  98. static void ususage P((void));
  99. static boolean fsxqt_file_read P((pointer puuconf, const char *zfile));
  100. static void usxqt_file_free P((void));
  101. static int isxqt_cmd P((pointer puuconf, int argc, char **argv, pointer pvar,
  102.             pointer pinfo));
  103. static int isxqt_file P((pointer puuconf, int argc, char **argv, pointer pvar,
  104.              pointer pinfo));
  105. static int isxqt_user P((pointer puuconf, int argc, char **argv, pointer pvar,
  106.              pointer pinfo));
  107. static boolean fsworkfiles P((pointer puuconf, int icmd, int csystems,
  108.                   char **pazsystems, boolean fnotsystems,
  109.                   int cusers, char **pazusers,
  110.                   boolean fnotusers, long iold, long iyoung,
  111.                   int ccommands, char **pazcommands,
  112.                   boolean fnotcommands, const char *zcomment,
  113.                   int cstdin));
  114. static boolean fsworkfiles_system P((pointer puuconf,int icmd,
  115.                      const struct uuconf_system *qsys,
  116.                      int cusers,  char **pazusers,
  117.                      boolean fnotusers, long iold,
  118.                      long iyoung, int ccommands,
  119.                      char **pazcommands,
  120.                      boolean fnotcommands,
  121.                      const char *zcomment, int cstdin));
  122. static boolean fsworkfile_show P((pointer puuconf, int icmd,
  123.                   const struct uuconf_system *qsys,
  124.                   const struct scmd *qcmd,
  125.                   long itime, int ccommands,
  126.                   char **pazcommands, boolean fnotcommands,
  127.                   const char *zcomment, int cstdin));
  128. static void usworkfile_header P((const struct uuconf_system *qsys,
  129.                  const struct scmd *qcmd,
  130.                  const char *zjobid,
  131.                  long itime, boolean ffirst));
  132. static boolean fsexecutions P((pointer puuconf, int icmd, int csystems,
  133.                    char **pazsystems, boolean fnotsystems,
  134.                    int cusers, char **pazusers,
  135.                    boolean fnotusers, long iold, long iyoung,
  136.                    int ccommands, char **pazcommands,
  137.                    boolean fnotcommands, const char *zcomment,
  138.                    int cstdin));
  139. static boolean fsnotify P((pointer puuconf, int icmd, const char *zcomment,
  140.                int cstdin, boolean fkilled, const char *zcmd,
  141.                struct scmdlist *qcmd, const char *zid,
  142.                const char *zuser,
  143.                const struct uuconf_system *qsys,
  144.                const char *zstdin, pointer pstdinseq,
  145.                const char *zrequestor));
  146. static boolean fsquery P((pointer puuconf));
  147. static int csunits_show P((long idiff));
  148. static boolean fsmachines P((void));
  149.  
  150. /* Long getopt options.  */
  151. static const struct option asSlongopts[] = { { NULL, 0, NULL, 0 } };
  152.  
  153. int
  154. main (argc, argv)
  155.      int argc;
  156.      char **argv;
  157. {
  158.   /* -a: list all jobs.  */
  159.   boolean fall = FALSE;
  160.   /* -B lines: number of lines of standard input to mail.  */
  161.   int cstdin = 100;
  162.   /* -c,-C command: list only specified command.  */
  163.   int ccommands = 0;
  164.   char **pazcommands = NULL;
  165.   boolean fnotcommands = FALSE;
  166.   /* -e: list execute jobs.  */
  167.   boolean fexecute = FALSE;
  168.   /* -k jobid: kill specified job.  */
  169.   int ckills = 0;
  170.   char **pazkills = NULL;
  171.   /* -m: report machine status.  */
  172.   boolean fmachine = FALSE;
  173.   /* -o hour: report jobs older than given number of hours.  */
  174.   int ioldhours = -1;
  175.   /* -p: report status of jobs holding lock files.  */
  176.   boolean fps = FALSE;
  177.   /* -q: list number of jobs for each system.  */
  178.   boolean fquery = FALSE;
  179.   /* -r jobid: rejuvenate specified job.  */
  180.   int crejuvs = 0;
  181.   char **pazrejuvs = NULL;
  182.   /* -s,-S system: list all jobs for specified system.  */
  183.   int csystems = 0;
  184.   char **pazsystems = NULL;
  185.   boolean fnotsystems = FALSE;
  186.   /* -u,-U user: list all jobs for specified user.  */
  187.   int cusers = 0;
  188.   char **pazusers = NULL;
  189.   boolean fnotusers = FALSE;
  190.   /* -W comment: comment to include in mail messages.  */
  191.   const char *zcomment = NULL;
  192.   /* -y hour: report jobs younger than given number of hours.  */
  193.   int iyounghours = -1;
  194.   /* -I file: set configuration file.  */
  195.   const char *zconfig = NULL;
  196.   /* -Q, -i, -K, -M, -N: what to do with each job.  */
  197.   int icmd = JOB_SHOW;
  198.   int ccmds;
  199.   int iopt;
  200.   pointer puuconf;
  201.   int iuuconf;
  202.   long iold;
  203.   long iyoung;
  204.   const char *azoneuser[1];
  205.   boolean fret;
  206.  
  207.   while ((iopt = getopt_long (argc, argv,
  208.                   "aB:c:C:eiI:k:KmMNo:pqQr:s:S:u:U:W:x:y:",
  209.                   asSlongopts, (int *) NULL)) != EOF)
  210.     {
  211.       switch (iopt)
  212.     {
  213.     case 'a':
  214.       /* List all jobs.  */
  215.       fall = TRUE;
  216.       break;
  217.  
  218.     case 'B':
  219.       /* Number of lines of standard input to mail.  */
  220.       cstdin = (int) strtol (optarg, (char **) NULL, 10);
  221.       break;
  222.  
  223.     case 'C':
  224.       /* List jobs for other than specified command.  */
  225.       fnotcommands = TRUE;
  226.       /* Fall through.  */
  227.     case 'c':
  228.       /* List specified command.  */
  229.       ++ccommands;
  230.       pazcommands = (char **) xrealloc ((pointer) pazcommands,
  231.                         ccommands * sizeof (char *));
  232.       pazcommands[ccommands - 1] = optarg;
  233.       break;
  234.  
  235.     case 'e':
  236.       /* List execute jobs.  */
  237.       fexecute = TRUE;
  238.       break;
  239.  
  240.     case 'i':
  241.       /* Prompt the user whether to kill each job.  */
  242.       icmd |= JOB_INQUIRE;
  243.       break;
  244.  
  245.     case 'I':
  246.       /* Set configuration file name.  */
  247.       if (fsysdep_other_config (optarg))
  248.         zconfig = optarg;
  249.       break;
  250.  
  251.     case 'k':
  252.       /* Kill specified job.  */
  253.       ++ckills;
  254.       pazkills = (char **) xrealloc ((pointer) pazkills,
  255.                      ckills * sizeof (char *));
  256.       pazkills[ckills - 1] = optarg;
  257.       break;
  258.  
  259.     case 'K':
  260.       /* Kill each listed job.  */
  261.       icmd |= JOB_KILL;
  262.       break;
  263.  
  264.     case 'm':
  265.       /* Report machine status.  */
  266.       fmachine = TRUE;
  267.       break;
  268.  
  269.     case 'M':
  270.       /* Mail to uucp action taken on each job.  */
  271.       icmd |= JOB_MAIL;
  272.       break;
  273.  
  274.     case 'N':
  275.       /*  Mail to requestor action taken on each job.  */
  276.       icmd |= JOB_NOTIFY;
  277.       break;
  278.  
  279.     case 'o':
  280.       /* Report old jobs.  */
  281.       ioldhours = (int) strtol (optarg, (char **) NULL, 10);
  282.       break;
  283.  
  284.     case 'p':
  285.       /* Get status of processes holding locks.  */
  286.       fps = TRUE;
  287.       break;
  288.  
  289.     case 'q':
  290.       /* List number of jobs for each system.  */
  291.       fquery = TRUE;
  292.       break;
  293.  
  294.     case 'Q':
  295.       /* Don't list jobs, just do -K processing.  */
  296.       icmd &=~ JOB_SHOW;
  297.       break;
  298.  
  299.     case 'r':
  300.       /* Rejuvenate specified job.  */
  301.       ++crejuvs;
  302.       pazrejuvs = (char **) xrealloc ((pointer) pazrejuvs,
  303.                       crejuvs * sizeof (char *));
  304.       pazrejuvs[crejuvs - 1] = optarg;
  305.       break;
  306.  
  307.     case 'S':
  308.       /* List jobs for other than specified system.  */
  309.       fnotsystems = TRUE;
  310.       /* Fall through.  */
  311.     case 's':
  312.       /* List jobs for specified system.  */
  313.       ++csystems;
  314.       pazsystems = (char **) xrealloc ((pointer) pazsystems,
  315.                        csystems * sizeof (char *));
  316.       pazsystems[csystems - 1] = optarg;
  317.       break;
  318.  
  319.     case 'U':
  320.       /* List jobs for other than specified user.  */
  321.       fnotusers = TRUE;
  322.       /* Fall through.  */
  323.     case 'u':
  324.       /* List jobs for specified user.  */
  325.       ++cusers;
  326.       pazusers = (char **) xrealloc ((pointer) pazusers,
  327.                      cusers * sizeof (char *));
  328.       pazusers[cusers - 1] = optarg;
  329.       break;
  330.  
  331.     case 'W':
  332.       /* Comment to include in mail messages.  */
  333.       zcomment = optarg;
  334.       break;
  335.  
  336.     case 'x':
  337. #if DEBUG > 1
  338.       /* Set debugging level.  */
  339.       iDebug |= idebug_parse (optarg);
  340. #endif
  341.       break;
  342.  
  343.     case 'y':
  344.       /* List jobs younger than given number of hours.  */
  345.       iyounghours = (int) strtol (optarg, (char **) NULL, 10);
  346.       break;
  347.  
  348.     case 0:
  349.       /* Long option found and flag set.  */
  350.       break;
  351.  
  352.     default:
  353.       ususage ();
  354.       break;
  355.     }
  356.     }
  357.  
  358.   if (optind != argc)
  359.     ususage ();
  360.  
  361.   /* To avoid confusion, most options are only permitted by
  362.      themselves.  This restriction might be removed later, but it is
  363.      imposed by most implementations.  We do permit any combination of
  364.      -c, -s, -u, -o and -y, and any combination of -k and -r.  */
  365.   ccmds = 0;
  366.   if (fall)
  367.     ++ccmds;
  368.   if (ckills > 0 || crejuvs > 0)
  369.     ++ccmds;
  370.   if (fmachine)
  371.     ++ccmds;
  372.   if (fps)
  373.     ++ccmds;
  374.   if (fquery)
  375.     ++ccmds;
  376.   if (fexecute || csystems > 0 || cusers > 0 || ioldhours != -1
  377.       || iyounghours != -1 || ccommands > 0)
  378.     ++ccmds;
  379.  
  380.   if (ccmds > 1)
  381.     {
  382.       ulog (LOG_ERROR, "Too many options");
  383.       ususage ();
  384.     }
  385.  
  386.   iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig);
  387.   if (iuuconf != UUCONF_SUCCESS)
  388.     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  389.  
  390. #if DEBUG > 1
  391.   {
  392.     const char *zdebug;
  393.  
  394.     iuuconf = uuconf_debuglevel (puuconf, &zdebug);
  395.     if (iuuconf != UUCONF_SUCCESS)
  396.       ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  397.     if (zdebug != NULL)
  398.       iDebug |= idebug_parse (zdebug);
  399.   }
  400. #endif
  401.  
  402.   usysdep_initialize (puuconf, INIT_SUID);
  403.  
  404.   /* If no commands were specified, we list all commands for the given
  405.      user.  */
  406.   if (ccmds == 0)
  407.     {
  408.       cusers = 1;
  409.       azoneuser[0] = zsysdep_login_name ();
  410.       pazusers = (char **) azoneuser;
  411.     }
  412.  
  413.   /* Canonicalize the system names.  */
  414.   if (csystems > 0)
  415.     {
  416.       int i;
  417.  
  418.       for (i = 0; i < csystems; i++)
  419.     {
  420.       struct uuconf_system ssys;
  421.  
  422.       iuuconf = uuconf_system_info (puuconf, pazsystems[i], &ssys);
  423.       if (iuuconf != UUCONF_SUCCESS)
  424.         {
  425.           if (iuuconf == UUCONF_NOT_FOUND)
  426.         ulog (LOG_FATAL, "%s: System not found", pazsystems[i]);
  427.           else
  428.         ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  429.         }
  430.       if (strcmp (pazsystems[i], ssys.uuconf_zname) != 0)
  431.         pazsystems[i] = zbufcpy (ssys.uuconf_zname);
  432.       (void) uuconf_system_free (puuconf, &ssys);
  433.     }
  434.     }
  435.  
  436.   if (ioldhours == -1)
  437.     iold = (long) -1;
  438.   else
  439.     {
  440.       iold = (ixsysdep_time ((long *) NULL)
  441.           - (long) ioldhours * (long) 60 * (long) 60);
  442.       if (iold < 0L)
  443.     iold = 0L;
  444.     }
  445.   if (iyounghours == -1)
  446.     iyoung = (long) -1;
  447.   else
  448.     {
  449.       iyoung = (ixsysdep_time ((long *) NULL)
  450.         - (long) iyounghours * (long) 60 * (long) 60);
  451.       if (iyoung < 0L)
  452.     iyoung = 0L;
  453.     }
  454.  
  455.   if (! fexecute
  456.       && (fall
  457.       || csystems > 0
  458.       || cusers > 0
  459.       || ioldhours != -1
  460.       || iyounghours != -1
  461.       || ccommands > 0))
  462.     fret = fsworkfiles (puuconf, icmd, csystems, pazsystems, fnotsystems,
  463.             cusers, pazusers, fnotusers, iold,  iyoung,
  464.             ccommands, pazcommands, fnotcommands, zcomment,
  465.             cstdin);
  466.   else if (fexecute)
  467.     fret = fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems,
  468.              cusers, pazusers, fnotusers, iold, iyoung,
  469.              ccommands, pazcommands, fnotcommands, zcomment,
  470.              cstdin);
  471.   else if (icmd != JOB_SHOW)
  472.     {
  473.       ulog (LOG_ERROR,
  474.         "-i, -K, -M, -N, -Q not supported with -k, -m, -p, -q, -r");
  475.       ususage ();
  476.       fret = FALSE;
  477.     }
  478.   else if (fquery)
  479.     fret = fsquery (puuconf);
  480.   else if (fmachine)
  481.     fret = fsmachines ();
  482.   else if (ckills > 0 || crejuvs > 0)
  483.     {
  484.       int i;
  485.  
  486.       fret = TRUE;
  487.       for (i = 0; i < ckills; i++)
  488.     if (! fsysdep_kill_job (puuconf, pazkills[i]))
  489.       fret = FALSE;
  490.  
  491.       for (i = 0; i < crejuvs; i++)
  492.     if (! fsysdep_rejuvenate_job (puuconf, pazrejuvs[i]))
  493.       fret = FALSE;
  494.     }
  495.   else if (fps)
  496.     fret = fsysdep_lock_status ();
  497.   else
  498.     {
  499. #if DEBUG > 0
  500.       ulog (LOG_FATAL, "Can't happen");
  501. #endif
  502.       fret = FALSE;
  503.     }
  504.  
  505.   ulog_close ();
  506.  
  507.   usysdep_exit (fret);
  508.  
  509.   /* Avoid errors about not returning a value.  */
  510.   return 0;
  511. }
  512.  
  513. /* Print a usage message and die.  */
  514.  
  515. static void
  516. ususage ()
  517. {
  518.   fprintf (stderr,
  519.        "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
  520.        VERSION);
  521.   fprintf (stderr,
  522.        "Usage: uustat [options]\n");
  523.   fprintf (stderr,
  524.        " -a: list all UUCP jobs\n");
  525.   fprintf (stderr, 
  526.        " -B num: number of lines to return in -M or -N mail message\n");
  527.   fprintf (stderr,
  528.        " -c command: list requests for named command\n");
  529.   fprintf (stderr,
  530.        " -C command: list requests for other than named command\n");
  531.   fprintf (stderr,
  532.        " -e: list queued executions rather than job requests\n");
  533.   fprintf (stderr,
  534.        " -i: prompt for whether to kill each listed job\n");
  535.   fprintf (stderr,
  536.        " -k job: kill specified UUCP job\n");
  537.   fprintf (stderr,
  538.        " -K: kill each listed job\n");
  539.   fprintf (stderr,
  540.        " -m: report status for all remote machines\n");
  541.   fprintf (stderr,
  542.        " -M: mail report on each listed job to UUCP administrator\n");
  543.   fprintf (stderr,
  544.        " -N: mail report on each listed job to requestor\n");
  545.   fprintf (stderr,
  546.        " -o hours: list all jobs older than given number of hours\n");
  547.   fprintf (stderr,
  548.        " -p: show status of all processes holding UUCP locks\n");
  549.   fprintf (stderr,
  550.        " -q: list number of jobs for each system\n");
  551.   fprintf (stderr,
  552.        " -Q: don't list jobs, just take actions (-i, -K, -M, -N)\n");
  553.   fprintf (stderr,
  554.        " -r job: rejuvenate specified UUCP job\n");
  555.   fprintf (stderr,
  556.        " -s system: list all jobs for specified system\n");
  557.   fprintf (stderr,
  558.        " -S system: list all jobs for other than specified system\n");
  559.   fprintf (stderr,
  560.        " -u user: list all jobs for specified user\n");
  561.   fprintf (stderr,
  562.        " -U user: list all jobs for other than specified user\n");
  563.   fprintf (stderr,
  564.        " -W comment: comment to include in mail messages\n");
  565.   fprintf (stderr,
  566.        " -y hours: list all jobs younger than given number of hours\n");
  567.   fprintf (stderr,
  568.        " -x debug: Set debugging level (0 for none, 9 is max)\n");
  569. #if HAVE_TAYLOR_CONFIG
  570.   fprintf (stderr,
  571.        " -I file: Set configuration file to use\n");
  572. #endif /* HAVE_TAYLOR_CONFIG */
  573.   exit (EXIT_FAILURE);
  574. }
  575.  
  576. /* We need to be able to read information from an execution file.  */
  577.  
  578. /* The user name extracted from an execution file.  */
  579. static char *zSxqt_user;
  580.  
  581. /* The system name from an execution file.  */
  582. static char *zSxqt_system;
  583.  
  584. /* Address of requesting user (who to send mail to).  */
  585. static const char *zSxqt_requestor;
  586.  
  587. /* The command (no arguments) from an execution file.  */
  588. static char *zSxqt_prog;
  589.  
  590. /* The full command line from an execution file.  */
  591. static char *zSxqt_cmd;
  592.  
  593. /* Number of files associated with an execution file.  */
  594. static int cSxqt_files;
  595.  
  596. /* Names of files associated with execution file.  */
  597. static char **pazSxqt_files;
  598.  
  599. /* Standard input file name.  */
  600. static const char *zSxqt_stdin;
  601.  
  602. /* A command table used to dispatch an execution file.  */
  603. static const struct uuconf_cmdtab asSxqt_cmds[] =
  604. {
  605.   { "C", UUCONF_CMDTABTYPE_FN | 0, NULL, isxqt_cmd },
  606.   { "I", UUCONF_CMDTABTYPE_STRING, (pointer) &zSxqt_stdin, NULL },
  607.   { "F", UUCONF_CMDTABTYPE_FN | 0, NULL, isxqt_file },
  608.   { "R", UUCONF_CMDTABTYPE_STRING, (pointer) &zSxqt_requestor, NULL },
  609.   { "U", UUCONF_CMDTABTYPE_FN | 3, NULL, isxqt_user },
  610.   { NULL, 0, NULL, NULL }
  611. };
  612.  
  613. /* Read an execution file, setting the above variables.  */
  614.  
  615. static boolean
  616. fsxqt_file_read (puuconf, zfile)
  617.      pointer puuconf;
  618.      const char *zfile;
  619. {
  620.   FILE *e;
  621.   int iuuconf;
  622.   boolean fret;
  623.  
  624.   e = fopen (zfile, "r");
  625.   if (e == NULL)
  626.     {
  627.       ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
  628.       return FALSE;
  629.     }
  630.  
  631.   zSxqt_user = NULL;
  632.   zSxqt_system = NULL;
  633.   zSxqt_stdin = NULL;
  634.   zSxqt_requestor = NULL;
  635.   zSxqt_prog = NULL;
  636.   zSxqt_cmd = NULL;
  637.   cSxqt_files = 0;
  638.   pazSxqt_files = NULL;
  639.  
  640.   iuuconf = uuconf_cmd_file (puuconf, e, asSxqt_cmds, (pointer) NULL,
  641.                  (uuconf_cmdtabfn) NULL,
  642.                  UUCONF_CMDTABFLAG_CASE, (pointer) NULL);
  643.   (void) fclose (e);
  644.   if (iuuconf == UUCONF_SUCCESS)
  645.     fret = TRUE;
  646.   else
  647.     {
  648.       ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  649.       fret = FALSE;
  650.     }
  651.  
  652.   if (zSxqt_user == NULL)
  653.     zSxqt_user = zbufcpy ("*unknown*");
  654.   if (zSxqt_system == NULL)
  655.     zSxqt_system = zbufcpy ("*unknown*");
  656.   if (zSxqt_prog == NULL)
  657.     {
  658.       zSxqt_prog = zbufcpy ("*none*");
  659.       zSxqt_cmd = zbufcpy ("*none*");
  660.     }
  661.  
  662.   return fret;
  663. }
  664.  
  665. /* Free up the information read from an execution file.  */
  666.  
  667. static void
  668. usxqt_file_free ()
  669. {
  670.   int i;
  671.  
  672.   ubuffree (zSxqt_user);
  673.   zSxqt_user = NULL;
  674.   ubuffree (zSxqt_system);
  675.   zSxqt_system = NULL;
  676.   ubuffree (zSxqt_prog);
  677.   zSxqt_prog = NULL;
  678.   ubuffree (zSxqt_cmd);
  679.   zSxqt_cmd = NULL;
  680.   for (i = 0; i < cSxqt_files; i++)
  681.     ubuffree (pazSxqt_files[i]);
  682.   cSxqt_files = 0;
  683.   xfree ((pointer) pazSxqt_files);
  684.   pazSxqt_files = NULL;
  685.   zSxqt_stdin = NULL;
  686.   zSxqt_requestor = NULL;
  687. }
  688.  
  689. /* Get the command from an execution file.  */
  690.  
  691. /*ARGSUSED*/
  692. static int
  693. isxqt_cmd (puuconf, argc, argv, pvar, pinfo)
  694.      pointer puuconf;
  695.      int argc;
  696.      char **argv;
  697.      pointer pvar;
  698.      pointer pinfo;
  699. {
  700.   size_t clen;
  701.   int i;
  702.  
  703.   if (argc <= 1)
  704.     return UUCONF_CMDTABRET_CONTINUE;
  705.  
  706.   zSxqt_prog = zbufcpy (argv[1]);
  707.  
  708.   clen = 0;
  709.   for (i = 1; i < argc; i++)
  710.     clen += strlen (argv[i]) + 1;
  711.  
  712.   zSxqt_cmd = zbufalc (clen);
  713.   zSxqt_cmd[0] = '\0';
  714.   for (i = 1; i < argc - 1; i++)
  715.     {
  716.       strcat (zSxqt_cmd, argv[i]);
  717.       strcat (zSxqt_cmd, " ");
  718.     }
  719.   strcat (zSxqt_cmd, argv[i]);
  720.  
  721.   return UUCONF_CMDTABRET_CONTINUE;
  722. }
  723.  
  724. /* Get the associated files from an execution file.  */
  725.  
  726. /*ARGSUSED*/
  727. static int
  728. isxqt_file (puuconf, argc, argv, pvar, pinfo)
  729.      pointer puuconf;
  730.      int argc;
  731.      char **argv;
  732.      pointer pvar;
  733.      pointer pinfo;
  734. {
  735.   if (argc != 2 && argc != 3)
  736.     return UUCONF_CMDTABRET_CONTINUE;
  737.  
  738.   /* If this file is not in the spool directory, just ignore it.  */
  739.   if (! fspool_file (argv[1]))
  740.     return UUCONF_CMDTABRET_CONTINUE;
  741.  
  742.   ++cSxqt_files;
  743.   pazSxqt_files = (char **) xrealloc ((pointer) pazSxqt_files,
  744.                       cSxqt_files * sizeof (char *));
  745.  
  746.   pazSxqt_files[cSxqt_files - 1] = zbufcpy (argv[1]);
  747.  
  748.   return UUCONF_CMDTABRET_CONTINUE;
  749. }
  750.  
  751. /* Get the requesting user and system from an execution file.  */
  752.  
  753. /*ARGSUSED*/
  754. static int
  755. isxqt_user (puuconf, argc, argv, pvar, pinfo)
  756.      pointer puuconf;
  757.      int argc;
  758.      char **argv;
  759.      pointer pvar;
  760.      pointer pinfo;
  761. {
  762.   zSxqt_user = zbufcpy (argv[1]);
  763.   zSxqt_system = zbufcpy (argv[2]);
  764.   return UUCONF_CMDTABRET_CONTINUE;
  765. }
  766.  
  767. /* Handle various possible requests to look at work files.  */
  768.  
  769. static boolean
  770. fsworkfiles (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers,
  771.          pazusers, fnotusers, iold, iyoung, ccommands, pazcommands,
  772.          fnotcommands, zcomment, cstdin)
  773.      pointer puuconf;
  774.      int icmd;
  775.      int csystems;
  776.      char **pazsystems;
  777.      boolean fnotsystems;
  778.      int cusers;
  779.      char **pazusers;
  780.      boolean fnotusers;
  781.      long iold;
  782.      long iyoung;
  783.      int ccommands;
  784.      char **pazcommands;
  785.      boolean fnotcommands;
  786.      const char *zcomment;
  787.      int cstdin;
  788. {
  789.   boolean fret;
  790.   int i;
  791.   int iuuconf;
  792.   struct uuconf_system ssys;
  793.  
  794.   fret = TRUE;
  795.  
  796.   if (csystems > 0 && ! fnotsystems)
  797.     {
  798.       for (i = 0; i < csystems; i++)
  799.     {
  800.       iuuconf = uuconf_system_info (puuconf, pazsystems[i], &ssys);
  801.       if (iuuconf != UUCONF_SUCCESS)
  802.         {
  803.           if (iuuconf == UUCONF_NOT_FOUND)
  804.         ulog (LOG_ERROR, "%s: System not found", pazsystems[i]);
  805.           else
  806.         ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  807.           fret = FALSE;
  808.           continue;
  809.         }
  810.  
  811.       if (! fsworkfiles_system (puuconf, icmd, &ssys, cusers, pazusers,
  812.                     fnotusers, iold, iyoung, ccommands,
  813.                     pazcommands, fnotcommands, zcomment,
  814.                     cstdin))
  815.         fret = FALSE;
  816.  
  817.       (void) uuconf_system_free (puuconf, &ssys);
  818.     }
  819.     }
  820.   else
  821.     {
  822.       char **pznames, **pz;
  823.  
  824.       iuuconf = uuconf_system_names (puuconf, &pznames, 0);
  825.       if (iuuconf != UUCONF_SUCCESS)
  826.     {
  827.       ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  828.       return FALSE;
  829.     }
  830.       
  831.       for (pz = pznames; *pz != NULL; pz++)
  832.     {
  833.       if (csystems > 0)
  834.         {
  835.           for (i = 0; i < csystems; i++)
  836.         if (strcmp (*pz, pazsystems[i]) == 0)
  837.           break;
  838.           if (i < csystems)
  839.         continue;
  840.         }
  841.  
  842.       iuuconf = uuconf_system_info (puuconf, *pz, &ssys);
  843.       if (iuuconf != UUCONF_SUCCESS)
  844.         {
  845.           ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  846.           fret = FALSE;
  847.           continue;
  848.         }
  849.  
  850.       if (! fsworkfiles_system (puuconf, icmd, &ssys, cusers, pazusers,
  851.                     fnotusers, iold, iyoung, ccommands,
  852.                     pazcommands, fnotcommands, zcomment,
  853.                     cstdin))
  854.         fret = FALSE;
  855.  
  856.       (void) uuconf_system_free (puuconf, &ssys);
  857.       xfree ((pointer) *pz);
  858.     }
  859.       xfree ((pointer) pznames);
  860.     }
  861.  
  862.   return fret;
  863. }
  864.  
  865. /* Look at the work files for a particular system.  */
  866.  
  867. static boolean
  868. fsworkfiles_system (puuconf, icmd, qsys, cusers, pazusers, fnotusers, iold,
  869.             iyoung, ccommands, pazcommands, fnotcommands, zcomment,
  870.             cstdin)
  871.      pointer puuconf;
  872.      int icmd;
  873.      const struct uuconf_system *qsys;
  874.      int cusers;
  875.      char **pazusers;
  876.      boolean fnotusers;
  877.      long iold;
  878.      long iyoung;
  879.      int ccommands;
  880.      char **pazcommands;
  881.      boolean fnotcommands;
  882.      const char *zcomment;
  883.      int cstdin;
  884. {
  885.   boolean fret;
  886.  
  887.   if (! fsysdep_get_work_init (qsys, UUCONF_GRADE_LOW))
  888.     return FALSE;
  889.  
  890.   while (TRUE)
  891.     {
  892.       struct scmd s;
  893.       long itime;
  894.  
  895.       if (! fsysdep_get_work (qsys, UUCONF_GRADE_LOW, &s))
  896.     {
  897.       usysdep_get_work_free (qsys);
  898.       return FALSE;
  899.     }
  900.       if (s.bcmd == 'H')
  901.     break;
  902.  
  903.       if (cusers > 0)
  904.     {
  905.       boolean fmatch;
  906.       int i;
  907.  
  908.       fmatch = fnotusers;
  909.       for (i = 0; i < cusers; i++)
  910.         {
  911.           if (s.zuser != NULL
  912.           && strcmp (pazusers[i], s.zuser) == 0)
  913.         {
  914.           fmatch = ! fmatch;
  915.           break;
  916.         }
  917.         }
  918.       if (! fmatch)
  919.         continue;
  920.     }
  921.  
  922.       itime = ixsysdep_work_time (qsys, s.pseq);
  923.  
  924.       if (iold != (long) -1 && itime > iold)
  925.     continue;
  926.  
  927.       if (iyoung != (long) -1 && itime < iyoung)
  928.     continue;
  929.  
  930.       if (! fsworkfile_show (puuconf, icmd, qsys, &s, itime, ccommands,
  931.                  pazcommands, fnotcommands, zcomment, cstdin))
  932.     {
  933.       usysdep_get_work_free (qsys);
  934.       return FALSE;
  935.     }
  936.     }
  937.  
  938.   fret = fsworkfile_show (puuconf, icmd, qsys, (const struct scmd *) NULL,
  939.               0L, ccommands, pazcommands, fnotcommands, zcomment,
  940.               cstdin);
  941.  
  942.   usysdep_get_work_free (qsys);
  943.  
  944.   return fret;
  945. }
  946.  
  947. /* Show a single workfile.  This is actually called once for each line
  948.    in the workfile, so we accumulate the lines and show them all at
  949.    once.  This lets us show an execution in a useful fashion.  */
  950.  
  951. static boolean
  952. fsworkfile_show (puuconf, icmd, qsys, qcmd, itime, ccommands, pazcommands,
  953.          fnotcommands, zcomment, cstdin)
  954.      pointer puuconf;
  955.      int icmd;
  956.      const struct uuconf_system *qsys;
  957.      const struct scmd *qcmd;
  958.      long itime;
  959.      int ccommands;
  960.      char **pazcommands;
  961.      boolean fnotcommands;
  962.      const char *zcomment;
  963.      int cstdin;
  964. {
  965.   static struct scmdlist *qlist;
  966.   static char *zlistid;
  967.   char *zid;
  968.  
  969.   if (qcmd == NULL)
  970.     zid = NULL;
  971.   else
  972.     {
  973.       zid = zsysdep_jobid (qsys, qcmd->pseq);
  974.       if (zid == NULL)
  975.     return FALSE;
  976.     }
  977.  
  978.   /* If this is the same jobid as the list, put it on the end.  */
  979.  
  980.   if (qcmd != NULL
  981.       && qlist != NULL
  982.       && strcmp (zlistid, zid) == 0)
  983.     {
  984.       struct scmdlist *qnew, **pq;
  985.  
  986.       ubuffree (zid);
  987.       qnew = (struct scmdlist *) xmalloc (sizeof (struct scmdlist));
  988.       qnew->qnext = NULL;
  989.       qnew->s = *qcmd;
  990.       qnew->itime = itime;
  991.       for (pq = &qlist; *pq != NULL; pq = &(*pq)->qnext)
  992.     ;
  993.       *pq = qnew;
  994.       return TRUE;
  995.     }
  996.  
  997.   /* Here we have found a different job ID, so we print the scmd
  998.      structures that we have accumulated.  We look for the special
  999.      case of an execution (an E command, or one of the destination
  1000.      files begins with X.).  We could be more clever about other
  1001.      situations as well.  */
  1002.   if (qlist != NULL)
  1003.     {
  1004.       boolean fmatch;
  1005.       const char *zprog, *zcmd, *zrequestor, *zstdin;
  1006.       char *zfree;
  1007.       struct scmdlist *qxqt;
  1008.       struct scmdlist *qfree;
  1009.  
  1010.       fmatch = FALSE;
  1011.       zprog = zcmd = zrequestor = zstdin = NULL;
  1012.       zfree = NULL;
  1013.  
  1014.       for (qxqt = qlist; qxqt != NULL; qxqt = qxqt->qnext)
  1015.     if (qxqt->s.bcmd == 'E'
  1016.         || (qxqt->s.bcmd == 'S'
  1017.         && qxqt->s.zto[0] == 'X'
  1018.         && qxqt->s.zto[1] == '.'
  1019.         && fspool_file (qxqt->s.zfrom)))
  1020.       break;
  1021.  
  1022.       if (qxqt == NULL)
  1023.     {
  1024.       if (ccommands == 0
  1025.           || (fnotcommands
  1026.           && strcmp (pazcommands[0], "ALL") == 0))
  1027.         {
  1028.           /* Show all the lines in a regular work file.  */
  1029.           fmatch = TRUE;
  1030.  
  1031.           if ((icmd & JOB_SHOW) != 0)
  1032.         {
  1033.           struct scmdlist *qshow;
  1034.  
  1035.           for (qshow = qlist; qshow != NULL; qshow = qshow->qnext)
  1036.             {
  1037.               char *zfile;
  1038.               long cbytes;
  1039.  
  1040.               usworkfile_header (qsys, &qshow->s, zlistid,
  1041.                      qshow->itime, qshow == qlist);
  1042.  
  1043.               switch (qshow->s.bcmd)
  1044.             {
  1045.             case 'S':
  1046.               if (strchr (qshow->s.zoptions, 'C') != NULL
  1047.                   || fspool_file (qshow->s.zfrom))
  1048.                 zfile = zsysdep_spool_file_name (qsys,
  1049.                                  qshow->s.ztemp,
  1050.                                  qshow->s.pseq);
  1051.               else
  1052.                 zfile = zbufcpy (qshow->s.zfrom);
  1053.               if (zfile == NULL)
  1054.                 cbytes = 0;
  1055.               else
  1056.                 {
  1057.                   cbytes = csysdep_size (zfile);
  1058.                   if (cbytes < 0)
  1059.                 cbytes = 0;
  1060.                 }
  1061.               printf ("Sending %s (%ld bytes) to %s",
  1062.                   qshow->s.zfrom, cbytes, qshow->s.zto);
  1063.               ubuffree (zfile);
  1064.               break;
  1065.             case 'R':
  1066.               printf ("Requesting %s to %s", qshow->s.zfrom,
  1067.                   qshow->s.zto);
  1068.               break;
  1069.             case 'X':
  1070.               printf ("Requesting %s to %s", qshow->s.zfrom,
  1071.                   qshow->s.zto);
  1072.               break;
  1073.             case 'P':
  1074.               printf ("(poll file)");
  1075.               break;
  1076. #if DEBUG > 0
  1077.             default:
  1078.               printf ("Bad line %d", qshow->s.bcmd);
  1079.               break;
  1080. #endif
  1081.             }
  1082.  
  1083.               printf ("\n");
  1084.             }
  1085.         }
  1086.         }
  1087.     }
  1088.       else
  1089.     {
  1090.       long csize;
  1091.       struct scmdlist *qsize;
  1092.  
  1093.       /* Show the command for an execution file.  */
  1094.       if (qxqt->s.bcmd == 'E')
  1095.         {
  1096.           zfree = zbufcpy (qxqt->s.zcmd);
  1097.           zfree[strcspn (zfree, " \t")] = '\0';
  1098.           zprog = zfree;
  1099.           zcmd = qxqt->s.zcmd;
  1100.           if (strchr (qxqt->s.zoptions, 'R') != NULL)
  1101.         zrequestor = qxqt->s.znotify;
  1102.         }
  1103.       else
  1104.         {
  1105.           char *zxqt;
  1106.  
  1107.           zxqt = zsysdep_spool_file_name (qsys, qxqt->s.zfrom,
  1108.                           qxqt->s.pseq);
  1109.           if (zxqt == NULL)
  1110.         return FALSE;
  1111.  
  1112.           if (! fsxqt_file_read (puuconf, zxqt))
  1113.         {
  1114.           ubuffree (zxqt);
  1115.           return FALSE;
  1116.         }
  1117.  
  1118.           ubuffree (zxqt);
  1119.  
  1120.           zprog = zSxqt_prog;
  1121.           zcmd = zSxqt_cmd;
  1122.           zrequestor = zSxqt_requestor;
  1123.         }
  1124.  
  1125.       csize = 0L;
  1126.       for (qsize = qlist; qsize != NULL; qsize = qsize->qnext)
  1127.         {
  1128.           if (qsize->s.bcmd == 'S' || qsize->s.bcmd == 'E')
  1129.         {
  1130.           char *zfile;
  1131.  
  1132.           if (strchr (qsize->s.zoptions, 'C') != NULL
  1133.               || fspool_file (qsize->s.zfrom))
  1134.             zfile = zsysdep_spool_file_name (qsys, qsize->s.ztemp,
  1135.                              qsize->s.pseq);
  1136.           else
  1137.             zfile = zbufcpy (qsize->s.zfrom);
  1138.           if (zfile != NULL)
  1139.             {
  1140.               long cbytes;
  1141.  
  1142.               cbytes = csysdep_size (zfile);
  1143.               if (cbytes > 0)
  1144.             csize += cbytes;
  1145.               ubuffree (zfile);
  1146.             }
  1147.         }
  1148.         }
  1149.  
  1150.       if (ccommands == 0)
  1151.         fmatch = TRUE;
  1152.       else
  1153.         {
  1154.           int i;
  1155.  
  1156.           fmatch = fnotcommands;
  1157.           for (i = 0; i < ccommands; i++)
  1158.         {
  1159.           if (strcmp (pazcommands[i], "ALL") == 0
  1160.               || strcmp (pazcommands[i], zprog) == 0)
  1161.             {
  1162.               fmatch = ! fmatch;
  1163.               break;
  1164.             }
  1165.         }
  1166.         }
  1167.  
  1168.       /* To get the name of the standard input file on this system
  1169.          we have to look through the list of file transfers to
  1170.          find the right one on the remote system.  */
  1171.       if (fmatch)
  1172.         {
  1173.           struct scmdlist *qstdin;
  1174.  
  1175.           if (qxqt->s.bcmd == 'E')
  1176.         qstdin = qxqt;
  1177.           else if (zSxqt_stdin != NULL)
  1178.         {
  1179.           for (qstdin = qlist;
  1180.                qstdin != NULL;
  1181.                qstdin = qstdin->qnext)
  1182.             if (qstdin->s.bcmd == 'S'
  1183.             && strcmp (qstdin->s.zto, zSxqt_stdin) == 0)
  1184.               break;
  1185.         }
  1186.           else
  1187.         qstdin = NULL;
  1188.  
  1189.           if (qstdin != NULL)
  1190.         {
  1191.           if (strchr (qstdin->s.zoptions, 'C') != NULL
  1192.               || fspool_file (qstdin->s.zfrom))
  1193.             zstdin = qstdin->s.ztemp;
  1194.           else
  1195.             zstdin = qstdin->s.zfrom;
  1196.         }
  1197.         }
  1198.  
  1199.       if (fmatch && (icmd & JOB_SHOW) != 0)
  1200.         {
  1201.           usworkfile_header (qsys, &qxqt->s, zlistid, qxqt->itime,
  1202.                  TRUE);
  1203.           printf ("Executing %s (sending %ld bytes)\n", zcmd, csize);
  1204.         }
  1205.     }
  1206.  
  1207.       if (fmatch)
  1208.     {
  1209.       boolean fkill;
  1210.  
  1211.       fkill = FALSE;
  1212.       if ((icmd & JOB_INQUIRE) != 0)
  1213.         {
  1214.           int b;
  1215.  
  1216.           /* Ask stdin whether this job should be killed.  */
  1217.           fprintf (stderr, "%s: Kill %s? ", abProgram, zlistid);
  1218.           (void) fflush (stderr);
  1219.           b = getchar ();
  1220.           fkill = b == 'y' || b == 'Y';
  1221.           while (b != EOF && b != '\n')
  1222.         b = getchar ();
  1223.         }
  1224.       else if ((icmd & JOB_KILL) != 0)
  1225.         fkill = TRUE;
  1226.           
  1227.       if (fkill
  1228.           && (qlist->s.zuser == NULL
  1229.           || strcmp (zsysdep_login_name (), qlist->s.zuser) != 0)
  1230.           && ! fsysdep_privileged ())
  1231.         ulog (LOG_ERROR, "%s: Not submitted by you", zlistid);
  1232.       else
  1233.         {
  1234.           if ((icmd & (JOB_MAIL | JOB_NOTIFY)) != 0)
  1235.         {
  1236.           if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill,
  1237.                   zcmd, qlist, zlistid, qlist->s.zuser,
  1238.                   qsys, zstdin, qlist->s.pseq, zrequestor))
  1239.             return FALSE;
  1240.         }
  1241.  
  1242.           if (fkill)
  1243.         {
  1244.           if (! fsysdep_kill_job (puuconf, zlistid))
  1245.             return FALSE;
  1246.         }
  1247.         }
  1248.     }
  1249.  
  1250.       if (qxqt != NULL)
  1251.     {
  1252.       if (qxqt->s.bcmd == 'E')
  1253.         ubuffree (zfree);
  1254.       else
  1255.         usxqt_file_free ();
  1256.     }
  1257.  
  1258.       /* Free up the list of entries.  */
  1259.       qfree = qlist;
  1260.       while (qfree != NULL)
  1261.     {
  1262.       struct scmdlist *qnext;
  1263.  
  1264.       qnext = qfree->qnext;
  1265.       xfree ((pointer) qfree);
  1266.       qfree = qnext;
  1267.     }
  1268.  
  1269.       ubuffree (zlistid);
  1270.  
  1271.       qlist = NULL;
  1272.       zlistid = NULL;
  1273.     }
  1274.  
  1275.   /* Start a new list with the entry we just got.  */
  1276.   if (qcmd != NULL)
  1277.     {
  1278.       qlist = (struct scmdlist *) xmalloc (sizeof (struct scmdlist));
  1279.       qlist->qnext = NULL;
  1280.       qlist->s = *qcmd;
  1281.       qlist->itime = itime;
  1282.       zlistid = zid;
  1283.     }
  1284.  
  1285.   return TRUE;
  1286. }
  1287.  
  1288. /* Show the header of the line describing a workfile.  */
  1289.  
  1290. static void
  1291. usworkfile_header (qsys, qcmd, zjobid, itime, ffirst)
  1292.      const struct uuconf_system *qsys;
  1293.      const struct scmd *qcmd;
  1294.      const char *zjobid;
  1295.      long itime;
  1296.      boolean ffirst;
  1297. {
  1298.   const char *zshowid;
  1299.   struct tm stime;
  1300.  
  1301.   if (ffirst)
  1302.     zshowid = zjobid;
  1303.   else
  1304.     zshowid = "-";
  1305.  
  1306.   printf ("%s %s %s ", zshowid, qsys->uuconf_zname,
  1307.       qcmd->zuser != NULL ? qcmd->zuser : OWNER);
  1308.  
  1309.   usysdep_localtime (itime, &stime);
  1310.   printf ("%02d-%02d %02d:%02d ",
  1311.       stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min);
  1312. }
  1313.  
  1314. /* List queued executions that have not been processed by uuxqt for
  1315.    one reason or another.  */
  1316.  
  1317. static boolean
  1318. fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers,
  1319.           pazusers, fnotusers, iold, iyoung, ccommands, pazcommands,
  1320.           fnotcommands, zcomment, cstdin)
  1321.      pointer puuconf;
  1322.      int icmd;
  1323.      int csystems;
  1324.      char **pazsystems;
  1325.      boolean fnotsystems;
  1326.      int cusers;
  1327.      char **pazusers;
  1328.      boolean fnotusers;
  1329.      long iold;
  1330.      long iyoung;
  1331.      int ccommands;
  1332.      char **pazcommands;
  1333.      boolean fnotcommands;
  1334.      const char *zcomment;
  1335.      int cstdin;
  1336. {
  1337.   const char *zlocalname;
  1338.   int iuuconf;
  1339.   char *zfile;
  1340.   char *zsystem;
  1341.   boolean ferr;
  1342.  
  1343.   iuuconf = uuconf_localname (puuconf, &zlocalname);
  1344.   if (iuuconf == UUCONF_NOT_FOUND)
  1345.     {
  1346.       zlocalname = zsysdep_localname ();
  1347.       if (zlocalname == NULL)
  1348.     return FALSE;
  1349.     }
  1350.   else if (iuuconf != UUCONF_SUCCESS)
  1351.     {
  1352.       ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1353.       return FALSE;
  1354.     }
  1355.  
  1356.   if (! fsysdep_get_xqt_init ())
  1357.     return FALSE;
  1358.  
  1359.   while ((zfile = zsysdep_get_xqt (&zsystem, &ferr)) != NULL)
  1360.     {
  1361.       boolean fmatch;
  1362.       int i;
  1363.       long itime;
  1364.  
  1365.       if (csystems > 0)
  1366.     {
  1367.       fmatch = fnotsystems;
  1368.       for (i = 0; i < csystems; i++)
  1369.         {
  1370.           if (strcmp (pazsystems[i], zsystem) == 0)
  1371.         {
  1372.           fmatch = ! fmatch;
  1373.           break;
  1374.         }
  1375.         }
  1376.       if (! fmatch)
  1377.         {
  1378.           ubuffree (zfile);
  1379.           ubuffree (zsystem);
  1380.           continue;
  1381.         }
  1382.     }
  1383.  
  1384.       itime = ixsysdep_file_time (zfile);
  1385.  
  1386.       if ((iold != (long) -1 && itime > iold)
  1387.       || (iyoung != (long) -1 && itime < iyoung))
  1388.     {
  1389.       ubuffree (zfile);
  1390.       ubuffree (zsystem);
  1391.       continue;
  1392.     }
  1393.  
  1394.       /* We need to read the execution file before we can check the
  1395.      user name.  */
  1396.       if (! fsxqt_file_read (puuconf, zfile))
  1397.     {
  1398.       ubuffree (zfile);
  1399.       ubuffree (zsystem);
  1400.       continue;      
  1401.     }
  1402.  
  1403.       if (cusers == 0)
  1404.     fmatch = TRUE;
  1405.       else
  1406.     {
  1407.       fmatch = fnotusers;
  1408.       for (i = 0; i < cusers; i++)
  1409.         {
  1410.           if (strcmp (zSxqt_user, pazusers[i]) == 0
  1411.           || (zSxqt_requestor != NULL
  1412.               && strcmp (zSxqt_requestor, pazusers[i]) == 0))
  1413.         {
  1414.           fmatch = ! fmatch;
  1415.           break;
  1416.         }
  1417.         }
  1418.     }
  1419.  
  1420.       if (fmatch && ccommands > 0)
  1421.     {
  1422.       fmatch = fnotcommands;
  1423.       for (i = 0; i < ccommands; i++)
  1424.         {
  1425.           if (strcmp (pazcommands[i], "ALL") == 0
  1426.           || strcmp (pazcommands[i], zSxqt_prog) == 0)
  1427.         {
  1428.           fmatch = ! fmatch;
  1429.           break;
  1430.         }
  1431.         }
  1432.     }
  1433.  
  1434.       if (fmatch)
  1435.     {
  1436.       boolean fbad, fkill;
  1437.       struct uuconf_system ssys;
  1438.  
  1439.       fbad = FALSE;
  1440.  
  1441.       if ((icmd & JOB_SHOW) != 0)
  1442.         {
  1443.           struct tm stime;
  1444.  
  1445.           printf ("%s %s!", zsystem, zSxqt_system);
  1446.           if (zSxqt_requestor != NULL)
  1447.         printf ("%s", zSxqt_requestor);
  1448.           else
  1449.         printf ("%s", zSxqt_user);
  1450.  
  1451.           usysdep_localtime (itime, &stime);
  1452.           printf (" %02d-%02d %02d:%02d ",
  1453.               stime.tm_mon + 1, stime.tm_mday, stime.tm_hour,
  1454.               stime.tm_min);
  1455.  
  1456.           printf ("%s\n", zSxqt_cmd);
  1457.         }
  1458.  
  1459.       fkill = FALSE;
  1460.       if ((icmd & JOB_INQUIRE) != 0)
  1461.         {
  1462.           int b;
  1463.  
  1464.           /* Ask stdin whether this job should be killed.  */
  1465.           fprintf (stderr, "%s: Kill %s? ", abProgram, zSxqt_cmd);
  1466.           (void) fflush (stderr);
  1467.           b = getchar ();
  1468.           fkill = b == 'y' || b == 'Y';
  1469.           while (b != EOF && b != '\n')
  1470.         b = getchar ();
  1471.         }
  1472.       else if ((icmd & JOB_KILL) != 0)
  1473.         fkill = TRUE;
  1474.  
  1475.       if (fkill)
  1476.         {
  1477.           if ((strcmp (zSxqt_user, zsysdep_login_name ()) != 0
  1478.            || strcmp (zsystem, zlocalname) != 0)
  1479.           && ! fsysdep_privileged ())
  1480.         {
  1481.           ulog (LOG_ERROR, "Job not submitted by you\n");
  1482.           fbad = TRUE;
  1483.         }
  1484.         }
  1485.  
  1486.       if (! fbad)
  1487.         {
  1488.           iuuconf = uuconf_system_info (puuconf, zsystem, &ssys);
  1489.           if (iuuconf != UUCONF_SUCCESS)
  1490.         {
  1491.           if (iuuconf != UUCONF_NOT_FOUND)
  1492.             {
  1493.               ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1494.               fbad = TRUE;
  1495.             }
  1496.           else if (strcmp (zsystem, zlocalname) == 0)
  1497.             {
  1498.               iuuconf = uuconf_system_local (puuconf, &ssys);
  1499.               if (iuuconf != UUCONF_SUCCESS)
  1500.             {
  1501.               ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1502.               fbad = TRUE;
  1503.             }
  1504.             }
  1505.           else if (! funknown_system (puuconf, zsystem, &ssys))
  1506.             {
  1507.               ulog (LOG_ERROR, "Job for unknown system %s",
  1508.                 zsystem);
  1509.               fbad = TRUE;
  1510.             }
  1511.         }
  1512.         }
  1513.  
  1514.       if (! fbad && (icmd & (JOB_MAIL | JOB_NOTIFY)) != 0)
  1515.         {
  1516.           if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill,
  1517.                   zSxqt_cmd, (struct scmdlist *) NULL,
  1518.                   (const char *) NULL, zSxqt_user, &ssys,
  1519.                   zSxqt_stdin, (pointer) NULL, zSxqt_requestor))
  1520.         {
  1521.           ferr = TRUE;
  1522.           usxqt_file_free ();
  1523.           ubuffree (zfile);
  1524.           ubuffree (zsystem);
  1525.           break;
  1526.         }
  1527.         }
  1528.  
  1529.       if (! fbad && fkill)
  1530.         {
  1531.           for (i = 0; i < cSxqt_files; i++)
  1532.         {
  1533.           char *z;
  1534.  
  1535.           z = zsysdep_spool_file_name (&ssys, pazSxqt_files[i],
  1536.                            (pointer) NULL);
  1537.           if (z != NULL)
  1538.             {
  1539.               (void) remove (z);
  1540.               ubuffree (z);
  1541.             }
  1542.         }
  1543.           if (remove (zfile) != 0)
  1544.         ulog (LOG_ERROR, "remove (%s): %s", zfile,
  1545.               strerror (errno));
  1546.         }
  1547.  
  1548.       if (! fbad)
  1549.         (void) uuconf_system_free (puuconf, &ssys);
  1550.     }
  1551.  
  1552.       usxqt_file_free ();
  1553.       ubuffree (zfile);
  1554.       ubuffree (zsystem);
  1555.     }
  1556.  
  1557.   usysdep_get_xqt_free ();
  1558.  
  1559.   return ferr;
  1560. }
  1561.  
  1562. /* When a job is killed, send mail to the appropriate people.  */
  1563.  
  1564. static boolean
  1565. fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser,
  1566.       qsys, zstdin, pstdinseq, zrequestor)
  1567.      pointer puuconf;
  1568.      int icmd;
  1569.      const char *zcomment;
  1570.      int cstdin;
  1571.      boolean fkilled;
  1572.      const char *zcmd;
  1573.      struct scmdlist *qcmd;
  1574.      const char *zid;
  1575.      const char *zuser;
  1576.      const struct uuconf_system *qsys;
  1577.      const char *zstdin;
  1578.      pointer pstdinseq;
  1579.      const char *zrequestor;
  1580. {
  1581.   const char **pz;
  1582.   int cgot;
  1583.   int i, istdin;
  1584.   const char *zsubject;
  1585.   boolean fret;
  1586.  
  1587.   pz = (const char **) xmalloc (20 * sizeof (const char *));
  1588.   cgot = 20;
  1589.  
  1590.   i = 0;
  1591.   if (zid == NULL)
  1592.     pz[i++] = "A UUCP execution request";
  1593.   else
  1594.     {
  1595.       pz[i++] = "UUCP job\n\t";
  1596.       pz[i++] = zid;
  1597.       pz[i++] = "\nfor system\n\t";
  1598.       pz[i++] = qsys->uuconf_zname;
  1599.     }
  1600.   pz[i++] = "\nrequested by\n\t";
  1601.   pz[i++] = zuser != NULL ? zuser : OWNER;
  1602.   if (zid == NULL)
  1603.     {
  1604.       pz[i++] = "\non system\n\t";
  1605.       pz[i++] = qsys->uuconf_zname;
  1606.     }
  1607.   pz[i++] = "\n";
  1608.  
  1609.   if (fkilled)
  1610.     pz[i++] = "has been killed.\n";
  1611.  
  1612.   if (zcomment != NULL)
  1613.     {
  1614.       pz[i++] = zcomment;
  1615.       pz[i++] = "\n";
  1616.     }
  1617.  
  1618.   pz[i++] = "The job ";
  1619.   if (fkilled)
  1620.     pz[i++] = "was\n";
  1621.   else
  1622.     pz[i++] = "is\n";
  1623.  
  1624.   if (zcmd != NULL)
  1625.     {
  1626.       pz[i++] = "\t";
  1627.       pz[i++] = zcmd;
  1628.     }
  1629.   else
  1630.     {
  1631.       struct scmdlist *qshow;
  1632.  
  1633.       for (qshow = qcmd; qshow != NULL; qshow = qshow->qnext)
  1634.     {
  1635.       if (i + 10 > cgot)
  1636.         {
  1637.           cgot += 20;
  1638.           pz = (const char **) xrealloc ((pointer) pz,
  1639.                          cgot * sizeof (const char *));
  1640.         }
  1641.  
  1642.       switch (qshow->s.bcmd)
  1643.         {
  1644.         case 'S':
  1645.           pz[i++] = "\tsend ";
  1646.           break;
  1647.         default:
  1648.         case 'R':
  1649.         case 'X':
  1650.           pz[i++] = "\trequest ";
  1651.           break;
  1652.         case 'P':
  1653.           pz[i++] = "\tpoll ";
  1654. #if DEBUG > 0
  1655.         case 'E':
  1656.           ulog (LOG_FATAL, "fsnotify: Can't happen");
  1657.           break;
  1658. #endif
  1659.         }
  1660.       if (qshow->s.zfrom != NULL && qshow->s.zto != NULL)
  1661.         {
  1662.           pz[i++] = qshow->s.zfrom;
  1663.           pz[i++] = " to ";
  1664.           pz[i++] = qshow->s.zto;
  1665.         }
  1666.     }
  1667.     }
  1668.  
  1669.   istdin = i;
  1670.   if (cstdin > 0 && zstdin != NULL)
  1671.     {
  1672.       boolean fspool;
  1673.       char *zfile;
  1674.       FILE *e;
  1675.  
  1676.       fspool = fspool_file (zstdin);
  1677.       if (fspool)
  1678.     zfile = zsysdep_spool_file_name (qsys, zstdin, pstdinseq);
  1679.       else
  1680.     zfile = zsysdep_local_file (zstdin, qsys->uuconf_zpubdir);
  1681.  
  1682.       if (zfile != NULL
  1683.       && (fspool
  1684.           || fin_directory_list (zfile, qsys->uuconf_pzremote_send,
  1685.                      qsys->uuconf_zpubdir, TRUE, TRUE,
  1686.                      (const char *) NULL)))
  1687.     {
  1688.       e = fopen (zfile, "r");
  1689.       if (e != NULL)
  1690.         {
  1691.           int clines, clen;
  1692.           char *zline;
  1693.           size_t cline;
  1694.  
  1695.           pz[i++] = "\n";
  1696.           istdin = i;
  1697.  
  1698.           clines = 0;
  1699.  
  1700.           zline = NULL;
  1701.           cline = 0;
  1702.           while ((clen = getline (&zline, &cline, e)) > 0)
  1703.         {
  1704.           if (memchr (zline, '\0', (size_t) clen) != NULL)
  1705.             {
  1706.               int ifree;
  1707.  
  1708.               /* A null character means this is probably a
  1709.              binary file.  */
  1710.               for (ifree = istdin; ifree < i; ifree++)
  1711.             ubuffree ((char *) pz[ifree]);
  1712.               i = istdin - 1;
  1713.               break;
  1714.             }
  1715.           ++clines;
  1716.           if (clines > cstdin)
  1717.             break;
  1718.           if (i >= cgot)
  1719.             {
  1720.               cgot += 20;
  1721.               pz = (const char **) xrealloc ((pointer) pz,
  1722.                              (cgot
  1723.                               * sizeof (char *)));
  1724.             }
  1725.           pz[i++] = zbufcpy (zline);
  1726.         }
  1727.           xfree ((pointer) zline);
  1728.           (void) fclose (e);
  1729.         }
  1730.     }
  1731.  
  1732.       ubuffree (zfile);
  1733.     }
  1734.  
  1735.   if (fkilled)
  1736.     zsubject = "UUCP job killed";
  1737.   else
  1738.     zsubject = "UUCP notification";
  1739.  
  1740.   fret = TRUE;
  1741.  
  1742.   if ((icmd & JOB_MAIL) != 0)
  1743.     {
  1744.       if (! fsysdep_mail (OWNER, zsubject, i, pz))
  1745.     fret = FALSE;
  1746.     }
  1747.  
  1748.   if ((icmd & JOB_NOTIFY) != 0
  1749.       && (zrequestor != NULL || zuser != NULL))
  1750.     {
  1751.       const char *zmail;
  1752.       char *zfree;
  1753.  
  1754.       if (zrequestor != NULL)
  1755.     zmail = zrequestor;
  1756.       else
  1757.     zmail = zuser;
  1758.  
  1759.       zfree = NULL;
  1760.  
  1761.       if (zid == NULL)
  1762.     {
  1763.       int iuuconf;
  1764.       const char *zloc;
  1765.  
  1766.       /* This is an execution request, which may be from another
  1767.          system.  If it is, we must prepend that system name to
  1768.          the user name extracted from the X. file.  */
  1769.       iuuconf = uuconf_localname (puuconf, &zloc);
  1770.       if (iuuconf == UUCONF_NOT_FOUND)
  1771.         {
  1772.           zloc = zsysdep_localname ();
  1773.           if (zloc == NULL)
  1774.         return FALSE;
  1775.         }
  1776.       else if (iuuconf != UUCONF_SUCCESS)
  1777.         ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
  1778.  
  1779.       if (strcmp (qsys->uuconf_zname, zloc) != 0
  1780. #if HAVE_INTERNET_MAIL
  1781.           && strchr (zmail, '@') == NULL
  1782. #endif
  1783.           )
  1784.         {
  1785.           zfree = zbufalc (strlen (qsys->uuconf_zname)
  1786.                    + strlen (zmail)
  1787.                    + sizeof "!");
  1788.           sprintf (zfree, "%s!%s", qsys->uuconf_zname, zmail);
  1789.           zmail = zfree;
  1790.         }
  1791.     }
  1792.  
  1793.       if (! fsysdep_mail (zmail, zsubject, i, pz))
  1794.     fret = FALSE;
  1795.  
  1796.       ubuffree (zfree);
  1797.     }
  1798.  
  1799.   while (istdin < i)
  1800.     {
  1801.       ubuffree ((char *) pz[istdin]);
  1802.       istdin++;
  1803.     }
  1804.  
  1805.   xfree ((pointer) pz);
  1806.  
  1807.   return fret;
  1808. }
  1809.  
  1810. /* Handle the -q option.  For each remote system this lists the number
  1811.    of jobs queued, the number of executions queued, and the current
  1812.    call status.  We get the executions all at once, because they are
  1813.    not accessed by system.  They could be, but it is possible to have
  1814.    executions pending for an unknown system, so special handling would
  1815.    still be required.  */
  1816.  
  1817. struct sxqtlist
  1818. {
  1819.   struct sxqtlist *qnext;
  1820.   char *zsystem;
  1821.   int cxqts;
  1822.   long ifirst;
  1823. };
  1824.  
  1825. /* These local functions need the definition of sxqtlist for the
  1826.    prototype.  */
  1827.  
  1828. static boolean fsquery_system P((const struct uuconf_system *qsys,
  1829.                  struct sxqtlist **pq,
  1830.                  long inow, const char *zlocalname));
  1831. static boolean fsquery_show P((const struct uuconf_system *qsys, int cwork,
  1832.                    long ifirstwork,
  1833.                    struct sxqtlist *qxqt,
  1834.                    long inow, const char *zlocalname));
  1835.  
  1836. static boolean
  1837. fsquery (puuconf)
  1838.      pointer puuconf;
  1839. {
  1840.   int iuuconf;
  1841.   const char *zlocalname;
  1842.   struct sxqtlist *qlist;
  1843.   char *zfile, *zsystem;
  1844.   boolean ferr;
  1845.   long inow;
  1846.   char **pznames, **pz;
  1847.   boolean fret;
  1848.  
  1849.   iuuconf = uuconf_localname (puuconf, &zlocalname);
  1850.   if (iuuconf == UUCONF_NOT_FOUND)
  1851.     {
  1852.       zlocalname = zsysdep_localname ();
  1853.       if (zlocalname == NULL)
  1854.     return FALSE;
  1855.     }
  1856.   else if (iuuconf != UUCONF_SUCCESS)
  1857.     {
  1858.       ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1859.       return FALSE;
  1860.     }
  1861.  
  1862.   /* Get a count of all the execution files.  */
  1863.   if (! fsysdep_get_xqt_init ())
  1864.     return FALSE;
  1865.  
  1866.   qlist = NULL;
  1867.   while ((zfile = zsysdep_get_xqt (&zsystem, &ferr)) != NULL)
  1868.     {
  1869.       struct sxqtlist *qlook;
  1870.  
  1871.       for (qlook = qlist; qlook != NULL; qlook = qlook->qnext)
  1872.     if (strcmp (zsystem, qlook->zsystem) == 0)
  1873.       break;
  1874.  
  1875.       if (qlook != NULL)
  1876.     {
  1877.       long itime;
  1878.  
  1879.       ubuffree (zsystem);
  1880.       ++qlook->cxqts;
  1881.       itime = ixsysdep_file_time (zfile);
  1882.       if (itime < qlook->ifirst)
  1883.         qlook->ifirst = itime;
  1884.     }
  1885.       else
  1886.     {
  1887.       struct sxqtlist *qnew;
  1888.  
  1889.       qnew = (struct sxqtlist *) xmalloc (sizeof (struct sxqtlist));
  1890.       qnew->qnext = qlist;
  1891.       qnew->zsystem = zsystem;
  1892.       qnew->cxqts = 1;
  1893.       qnew->ifirst = ixsysdep_file_time (zfile);
  1894.       qlist = qnew;
  1895.     }
  1896.  
  1897.       ubuffree (zfile);
  1898.     }
  1899.  
  1900.   usysdep_get_xqt_free ();
  1901.  
  1902.   if (ferr)
  1903.     return FALSE;
  1904.  
  1905.   inow = ixsysdep_time ((long *) NULL);
  1906.  
  1907.   /* Show the information for each system.  */
  1908.   iuuconf = uuconf_system_names (puuconf, &pznames, 0);
  1909.   if (iuuconf != UUCONF_SUCCESS)
  1910.     {
  1911.       ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1912.       return FALSE;
  1913.     }
  1914.  
  1915.   fret = TRUE;
  1916.  
  1917.   for (pz = pznames; *pz != NULL; pz++)
  1918.     {
  1919.       struct uuconf_system ssys;
  1920.  
  1921.       iuuconf = uuconf_system_info (puuconf, *pz, &ssys);
  1922.       if (iuuconf != UUCONF_SUCCESS)
  1923.     {
  1924.       ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1925.       fret = FALSE;
  1926.       continue;
  1927.     }
  1928.  
  1929.       if (! fsquery_system (&ssys, &qlist, inow, zlocalname))
  1930.     fret = FALSE;
  1931.  
  1932.       (void) uuconf_system_free (puuconf, &ssys);
  1933.       xfree ((pointer) *pz);
  1934.     }
  1935.  
  1936.   /* Check for the local system in the list of execution files.  */
  1937.   if (qlist != NULL)
  1938.     {
  1939.       struct sxqtlist **pq;
  1940.  
  1941.       for (pq = &qlist; *pq != NULL; pq = &(*pq)->qnext)
  1942.     {
  1943.       if (strcmp ((*pq)->zsystem, zlocalname) == 0)
  1944.         {
  1945.           struct uuconf_system ssys;
  1946.           struct sxqtlist *qfree;
  1947.  
  1948.           iuuconf = uuconf_system_info (puuconf, zlocalname, &ssys);
  1949.           if (iuuconf != UUCONF_SUCCESS)
  1950.         {
  1951.           if (iuuconf != UUCONF_NOT_FOUND)
  1952.             {
  1953.               ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1954.               fret = FALSE;
  1955.               break;
  1956.             }
  1957.  
  1958.           iuuconf = uuconf_system_local (puuconf, &ssys);
  1959.           if (iuuconf != UUCONF_SUCCESS)
  1960.             {
  1961.               ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1962.               fret = FALSE;
  1963.               break;
  1964.             }
  1965.           ssys.uuconf_zname = (char *) zlocalname;
  1966.         }
  1967.  
  1968.           if (! fsquery_show (&ssys, 0, 0L, *pq, inow, zlocalname))
  1969.         fret = FALSE;
  1970.           (void) uuconf_system_free (puuconf, &ssys);
  1971.           qfree = *pq;
  1972.           *pq = qfree->qnext;
  1973.           ubuffree (qfree->zsystem);
  1974.           xfree ((pointer) qfree);
  1975.           break;
  1976.         }
  1977.     }
  1978.     }
  1979.  
  1980.   /* Print out information for any unknown systems for which we have
  1981.      execution files.  */
  1982.   while (qlist != NULL)
  1983.     {
  1984.       struct uuconf_system ssys;
  1985.       struct sxqtlist *qnext;
  1986.  
  1987.       if (! funknown_system (puuconf, qlist->zsystem, &ssys))
  1988.     {
  1989.       ulog (LOG_ERROR, "Executions queued up for unknown systems");
  1990.       fret = FALSE;
  1991.       break;
  1992.     }
  1993.  
  1994.       if (! fsquery_show (&ssys, 0, 0L, qlist, inow, zlocalname))
  1995.     fret = FALSE;
  1996.       (void) uuconf_system_free (puuconf, &ssys);
  1997.       qnext = qlist->qnext;
  1998.       ubuffree (qlist->zsystem);
  1999.       xfree ((pointer) qlist);
  2000.       qlist = qnext;
  2001.     }
  2002.  
  2003.   return fret;
  2004. }
  2005.  
  2006. /* Query a single known system.  */
  2007.  
  2008. static boolean
  2009. fsquery_system (qsys, pq, inow, zlocalname)
  2010.      const struct uuconf_system *qsys;
  2011.      struct sxqtlist **pq;
  2012.      long inow;
  2013.      const char *zlocalname;
  2014. {
  2015.   int cwork;
  2016.   long ifirstwork;
  2017.   char *zid;
  2018.   boolean fret;
  2019.  
  2020.   if (! fsysdep_get_work_init (qsys, UUCONF_GRADE_LOW))
  2021.     return FALSE;
  2022.  
  2023.   cwork = 0;
  2024.   ifirstwork = 0L;
  2025.   zid = NULL;
  2026.   while (TRUE)
  2027.     {
  2028.       struct scmd s;
  2029.       long itime;
  2030.       char *zthisid;
  2031.  
  2032.       if (! fsysdep_get_work (qsys, UUCONF_GRADE_LOW, &s))
  2033.     return FALSE;
  2034.       if (s.bcmd == 'H')
  2035.     break;
  2036.  
  2037.       zthisid = zsysdep_jobid (qsys, s.pseq);
  2038.       if (zid != NULL && strcmp (zid, zthisid) == 0)
  2039.     ubuffree (zthisid);
  2040.       else
  2041.     {
  2042.       ++cwork;
  2043.       ubuffree (zid);
  2044.       zid = zthisid;
  2045.     }
  2046.  
  2047.       itime = ixsysdep_work_time (qsys, s.pseq);
  2048.       if (ifirstwork == 0L || ifirstwork > itime)
  2049.     ifirstwork = itime;
  2050.     }
  2051.  
  2052.   usysdep_get_work_free (qsys);
  2053.   ubuffree (zid);
  2054.  
  2055.   /* Find the execution information, if any.  */
  2056.   while (*pq != NULL)
  2057.     {
  2058.       if (strcmp ((*pq)->zsystem, qsys->uuconf_zname) == 0)
  2059.     break;
  2060.       pq = &(*pq)->qnext;
  2061.     }
  2062.  
  2063.   /* If there are no commands and no executions, don't print any
  2064.      information for this system.  */
  2065.   if (cwork == 0 && *pq == NULL)
  2066.     return TRUE;
  2067.  
  2068.   fret = fsquery_show (qsys, cwork, ifirstwork, *pq, inow, zlocalname);
  2069.  
  2070.   if (*pq != NULL)
  2071.     {
  2072.       struct sxqtlist *qfree;
  2073.  
  2074.       qfree = *pq;
  2075.       *pq = qfree->qnext;
  2076.       ubuffree (qfree->zsystem);
  2077.       xfree ((pointer) qfree);
  2078.     }
  2079.  
  2080.   return fret;
  2081. }
  2082.  
  2083. /* Print out the query information for a single system.  We handle the
  2084.    local system specially.  */
  2085.  
  2086. static boolean
  2087. fsquery_show (qsys, cwork, ifirstwork, qxqt, inow, zlocalname)
  2088.      const struct uuconf_system *qsys;
  2089.      int cwork;
  2090.      long ifirstwork;
  2091.      struct sxqtlist *qxqt;
  2092.      long inow;
  2093.      const char *zlocalname;
  2094. {
  2095.   boolean flocal;
  2096.   struct sstatus sstat;
  2097.   boolean fnostatus;
  2098.   struct tm stime;
  2099.   int cpad;
  2100.  
  2101.   flocal = strcmp (qsys->uuconf_zname, zlocalname) == 0;
  2102.  
  2103.   if (! flocal)
  2104.     {
  2105.       if (! fsysdep_get_status (qsys, &sstat, &fnostatus))
  2106.     return FALSE;
  2107.     }
  2108.  
  2109.   printf ("%-10s %3dC (", qsys->uuconf_zname, cwork);
  2110.  
  2111.   if (cwork == 0)
  2112.     {
  2113.       printf ("0 secs");
  2114.       cpad = 3;
  2115.     }
  2116.   else
  2117.     cpad = csunits_show (inow - ifirstwork);
  2118.  
  2119.   printf (") ");
  2120.   while (cpad-- != 0)
  2121.     printf (" ");
  2122.  
  2123.   if (qxqt == NULL)
  2124.     printf ("  0X (0 secs)  ");
  2125.   else
  2126.     {
  2127.       printf ("%3dX (", qxqt->cxqts);
  2128.       cpad = csunits_show (inow - qxqt->ifirst);
  2129.       printf (")");
  2130.       while (cpad-- != 0)
  2131.     printf (" ");
  2132.     }
  2133.  
  2134.   if (flocal || fnostatus)
  2135.     {
  2136.       printf ("\n");
  2137.       return TRUE;
  2138.     }
  2139.  
  2140.   usysdep_localtime (sstat.ilast, &stime);
  2141.  
  2142.   printf (" %02d-%02d %02d:%02d ", 
  2143.       stime.tm_mon + 1,stime.tm_mday, stime.tm_hour, stime.tm_min);
  2144.  
  2145.   printf ("%s\n", azStatus[(int) sstat.ttype]);
  2146.  
  2147.   return TRUE;
  2148. }
  2149.  
  2150. /* Print a time difference in the largest applicable units.  */
  2151.  
  2152. static int
  2153. csunits_show (idiff)
  2154.      long idiff;
  2155. {
  2156.   const char *zunit;
  2157.   long iunits;
  2158.   int cpad;
  2159.  
  2160.   if (idiff > (long) 24 * (long) 60 * (long) 60)
  2161.     {
  2162.       iunits = idiff / ((long) 24 * (long) 60 * (long) 60);
  2163.       zunit = "day";
  2164.       cpad = 4;
  2165.     }
  2166.   else if (idiff > (long) 60 * 60)
  2167.     {
  2168.       iunits = idiff / (long) (60 * 60);
  2169.       zunit = "hour";
  2170.       cpad = 3;
  2171.     }
  2172.   else if (idiff > (long) 60)
  2173.     {
  2174.       iunits = idiff / (long) 60;
  2175.       zunit = "min";
  2176.       cpad = 4;
  2177.     }
  2178.   else
  2179.     {
  2180.       iunits = idiff;
  2181.       zunit = "sec";
  2182.       cpad = 4;
  2183.     }
  2184.  
  2185.   printf ("%ld %s%s", iunits, zunit, iunits == 1 ? "" : "s");
  2186.  
  2187.   if (iunits != 1)
  2188.     --cpad;
  2189.   if (iunits > 99)
  2190.     --cpad;
  2191.   if (iunits > 9)
  2192.     --cpad;
  2193.   return cpad;
  2194. }
  2195.  
  2196. /* Give a list of all status entries for all machines that we have
  2197.    status entries for.  We need to get a list of status entries in a
  2198.    system dependent fashion, since we may have status for unknown
  2199.    systems.  */
  2200.  
  2201. static boolean
  2202. fsmachines ()
  2203. {
  2204.   pointer phold;
  2205.   char *zsystem;
  2206.   boolean ferr;
  2207.   struct sstatus sstat;
  2208.  
  2209.   if (! fsysdep_all_status_init (&phold))
  2210.     return FALSE;
  2211.  
  2212.   while ((zsystem = zsysdep_all_status (phold, &ferr, &sstat)) != NULL)
  2213.     {
  2214.       struct tm stime;
  2215.  
  2216.       usysdep_localtime (sstat.ilast, &stime);
  2217.       printf ("%-14s %02d-%02d %02d:%02d %s", zsystem,
  2218.           stime.tm_mon + 1, stime.tm_mday, stime.tm_hour,
  2219.           stime.tm_min, azStatus[(int) sstat.ttype]);
  2220.       ubuffree (zsystem);
  2221.       if (sstat.ttype != STATUS_TALKING
  2222.       && sstat.cwait > 0)
  2223.     {
  2224.       printf (" (%d %s", sstat.cretries,
  2225.           sstat.cretries == 1 ? "try" : "tries");
  2226.       if (sstat.ilast + sstat.cwait > ixsysdep_time ((long *) NULL))
  2227.         {
  2228.           usysdep_localtime (sstat.ilast + sstat.cwait, &stime);
  2229.           printf (", next after %02d-%02d %02d:%02d",
  2230.               stime.tm_mon + 1, stime.tm_mday, stime.tm_hour,
  2231.               stime.tm_min);
  2232.         }
  2233.       printf (")");
  2234.     }
  2235.       printf ("\n");
  2236.     }
  2237.  
  2238.   usysdep_all_status_free (phold);
  2239.  
  2240.   return ! ferr;
  2241. }
  2242.